/*
 * @Author: chenzenghua
 * @Date: 2022-12-02 10:12:02
 * @LastEditTime: 2024-05-29 13:40:36
 * @LastEditors: Harity
 * @Description:
 */
import axios, { AxiosRequestConfig } from 'axios'
import { Msg } from '@/components/Msg';
import NProgress from 'nprogress'
import globalAction from '@/store/globalAction'
import appSettings from '../../config/appSettings'

/**
 * 续签地址,自行修改
 */
const renewTokenUrl = appSettings.renewTokenUrl
const codeMessage: any = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队（异步任务）。',
  204: '删除数据成功。',
  400: '发出的请求缺乏参数或参数格式不正确。',
  401: '用户没有权限（令牌、用户名、密码错误）。',
  403: '用户得到授权，但是访问是被禁止的。你可能无权限访问该接口。',
  404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除，且不会再得到的。',
  422: '当创建一个对象时，发生一个验证错误。',
  429: '您的操作过于频繁。',
  500: '服务器发生错误，请检查服务器。',
  502: '网关错误。',
  503: '服务不可用，服务器暂时过载或维护。',
  504: '网关超时。',
}

const debug = process.env.NODE_ENV === 'development'

/**
 * 请求参数格式定义
 */
export interface IRequestProps {
  url: string
  /**
   * @default GET
   */
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
  params?: any
  data?: any
  disableErrorAlerm?: boolean
  axiosOptions?: AxiosRequestConfig<any>
  disableLoading?: boolean
  /**
   * 返回原始相应内容 不做任何处理
   */
  getResponse?: boolean
}
const sleep = (milliseconds: number) => {
  return new Promise((resolve) => {
    setTimeout(resolve, milliseconds)
  })
}
let refreshSignal = 0
let loadingCounter = 0
const getAccessToken = () => sessionStorage.getItem('AccessToken') || ''
const getRefreshToken = () => sessionStorage.getItem('RefreshToken') || ''
const setAccessToken = (accessToken: string) => sessionStorage.setItem('AccessToken', accessToken)
const settRefreshToken = (refreshToken: string) => sessionStorage.setItem('RefreshToken', refreshToken)
const logGreen = (str: string) => console.log(`%c ::${str}`, 'background:#12b405;color:#444857')
const logYellow = (str: string) => console.log(`%c ::${str}`, 'background:#fff000;color:#444857')
const logRed = (str: string) => console.log(`%c ::${str}`, 'background:#da1b60;color:white')
//一般实例
const instance = axios.create({
  validateStatus: function (status) {
    return true //自行处理错误
  },
})

//token续约实例
const instanceTokenRenew = axios.create({
  validateStatus: function (status) {
    return true //自行处理错误
  },
  method: 'get',
})
//阻塞等待续约完成信号
async function checkSignal() {
  while (refreshSignal) {
    if (refreshSignal === 0) {
      break
    }
    await sleep(50)
  }
}

const XRequset = async <T = any>(p: IRequestProps) => {
  //请求拦截器
  instance.interceptors.request.use(function (config: any) {
    config.headers = {
      ...config.headers,
      'Content-Type': config.headers['Content-Type'] || 'application/json',
      Authorization: 'Bearer ' + getAccessToken(),
    }
    return config
  })
  const options: AxiosRequestConfig = {
    method: p.method || 'GET',
    url: p.url,
    params: p.params || undefined,
    // paramsSerializer: function (params) {
    //   return Qs.stringify(params, { arrayFormat: 'brackets' })
    // },
    //其他axios参数
    data: p.data || undefined,
    ...p.axiosOptions,
  }

  //返回promise
  return new Promise<T>((resolve, reject) => {
    loadingCounter++
    NProgress.start()
    instance
      .request(options)
      .then(async (res) => {
        //重发方法
        const resend = (config: any) => {
          logYellow('重发请求:' + config.url)
          instance.request(config).then((res_resend) => {
            if (res_resend.status < 300) {
              const { data, exception, msg, success } = res_resend.data
              if (success) {
                if (debug) {
                  console.groupCollapsed(`%c Sucess: ${p.url}`, 'background:#12b405;color:#ffffff')
                  console.log('Request:', p)
                  console.log('Respose:', res)
                  console.groupEnd()
                }
                resolve(data)
              } else {
                logRed('[重发]请求成功,但是服务器返回了错误:' + `[${res_resend.config.url}]` + msg)
                console.log(res_resend)
                if (!p.disableErrorAlerm) {
                  Msg.error('请求出错:' + msg, { duration: 5, description: exception || undefined })
                }
                reject(msg)
              }
            } else {
              const { data, exception, msg } = res_resend.data
              const msgout = `[${res_resend.status}]${codeMessage[res_resend.status] || ''} ${msg || ''}`
              if (!p.disableErrorAlerm) {
                Msg.error('请求错误:' + msgout, { duration: 5, description: exception || undefined })
              }
              console.log(res_resend)
              reject(msgout)
            }
          })
        }
        switch (true) {
          case res.status === 401:
            if (refreshSignal === 0) {
              refreshSignal = 1
              //无权限 续签token
              if (!getAccessToken() || !getRefreshToken()) {
                reject()
                console.log('引导到统一登录')
                let log_url = localStorage.getItem('unit_log_url')
                //跳转到统一登录页
                const x =
                  log_url +
                  `?module_id=${appSettings.moduleId}&redirect_url=${encodeURIComponent(
                    window.location.origin + '/redirect_url',
                  )}`
                location.href = x
              } else {
                logYellow('尝试续签token...' + res.config.url)
                const resToken = await instanceTokenRenew.request({
                  url: renewTokenUrl,
                  params: {
                    expriedToken: getAccessToken(),
                    refreshToken: getRefreshToken(),
                  },
                })
                if (resToken.status >= 300) {
                  console.log('续签失败,返回登录页')
                  reject(resToken)
                  globalAction.onLogoff()

                } else {
                  const { AccessToken, RefreshToken, ExpiresTime } = resToken?.data?.data
                  logGreen('续签成功,更新token,过期时间:' + ExpiresTime)
                  if (!AccessToken || !RefreshToken) {
                    globalAction.onLogoff()
                  } else {
                    setAccessToken(AccessToken)
                    settRefreshToken(RefreshToken)
                    refreshSignal = 0
                    //重发请求
                    resend(res.config)
                  }
                }
              }
            } else {
              logYellow('正在等待续签任务完成..')
              await checkSignal()
              resend(res.config)
            }

            break
          case res.status >= 404: //服务器错误
            {
              const { exception, msg } = res.data
              const msgout = `[${res.status}]${codeMessage[res.status] || ''} ${msg || ''}`
              if (!p.disableErrorAlerm) {
                Msg.error('请求错误:' + msgout, { duration: 5000, description: exception || undefined })
              }
              reject(msgout)
            }
            break
          case res.status < 300:
            {
              const { data, exception, msg, success } = res.data
              if (p.getResponse) {
                resolve(res.data)
              } else {
                if (success) {
                  if (debug) {
                    console.groupCollapsed(`%c Sucess: ${p.url}`, 'background:#12b405;color:#ffffff')
                    console.log('Request:', p)
                    console.log('Respose:', res)
                    console.groupEnd()
                  }

                  resolve(data)
                } else {
                  logRed('请求成功,但是服务器返回了错误:' + `[${res.config.url}]` + msg)
                  console.log(res)
                  if (!p.disableErrorAlerm) {
                    Msg.error('请求出错:' + msg, { duration: 5000, description: exception || undefined })
                  }
                  reject(msg)
                }
              }
            }
            break
          default:
            console.log('未知错误')
            console.log(res)
            reject(res)
            break
        }
      })
      .catch((e) => {
        console.log('Request Err', e)
      })
      .finally(() => {
        loadingCounter--
        if (loadingCounter <= 0) {
          NProgress.done()
        }
      })
  })
}

export default XRequset
